#include "characters/Player.hh"
#include "characters/Character.hh"
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <stdexcept>
using std::string;

// --- Constructor ---
Player::Player(const std::string &name)
    : Character(name, "A brave reporter searching for the truth.", 1000, 1200, 80, 80),
      flashlightOn(true), flashlightBroken(false)
{
    inventory.reserve(MAX_INVENTORY_CAPACITY);
    item_number = {0};
}

// --- Destructor ---
Player::~Player()
{
    for (Item *itemPtr : inventory)
    {
        delete itemPtr;
    }
    inventory.clear();
}

Player &Player::operator++()
{
    this->attackPower += 50;
    this->defensePower += 50;

    std::cout << "Your attack power increased by 20 and defense power increased by 10." << std::endl;
    std::cout << "New Attack Power: " << this->attackPower << std::endl;
    std::cout << "New Defense Power: " << this->defensePower << std::endl;

    return *this;
}

// --- Overridden Methods ---
bool Player::attack(ICharacter &target)
{
    if (!isAlive())
    {
        std::cout << getName() << " cannot attack, they are incapacitated!" << std::endl;
        return false;
    }
    if (!target.isAlive())
    {
        std::cout << target.getName() << " is already defeated." << std::endl;
        return false;
    }

    std::cout << getName() << " attacks " << target.getName() << "!" << std::endl;
    std::cout << "Do you want to use items(y/n)? " << std::endl;
    char input, num;
    std::cout << "> " << std::endl;
    std::cin >> input;

    unsigned damageDealt = getAttackPower();
    if (input == 'y')
    {
        std::cout << "Which items do you want to use?" << std::endl;
        std::cin >> num;
        while (num != '1' && num != '2')
        {
            std::cout << "It's not the time to use it" << std::endl;
            std::cout << "Which items do you want to use?" << std::endl;
            std::cin >> num;
        }
        damageDealt = this->inventory[num]->getAttackBonus();
    }
    bool targetSurvived = target.takeDamage(damageDealt);

    if (!targetSurvived)
    {
        std::cout << getName() << " defeated " << target.getName() << "!" << std::endl;
    }
    return targetSurvived;
}

void Player::addToInventory(Item *item)
{
    if (!item)
    {
        std::cerr << "[Error] Tried to add a null item to inventory." << std::endl;
        return;
    }

    if (inventory.size() >= MAX_INVENTORY_CAPACITY)
    {
        std::cout << "Inventory is full! Cannot pick up " << item->getName() << "." << std::endl;
        delete item;
    }
    else
    {
        bool newitem = true;
        for (int i = 0; i < inventory.size(); i++)
        {
            if (item->getName() == inventory[i]->getName())
            {
                newitem = false;
                break;
            }
        }
        if (newitem)
        {
            std::cout << "You picked up: " << item->getName() << " (" << item->getDescription() << ")" << std::endl;
            inventory.push_back(item);
            if (item->getName() == "Heavy Textbook")
            {
                applyItemPassiveEffect(*item);
            }
        }
    }
}

void Player::displayInventory() const
{
    std::cout << "\n--- " << getName() << "'s Inventory (" << inventory.size() << "/" << MAX_INVENTORY_CAPACITY << ") ---" << std::endl;
    if (inventory.empty())
    {
        std::cout << "Inventory is empty." << std::endl;
    }
    else
    {
        for (size_t i = 0; i < inventory.size(); ++i)
        {
            if (inventory[i])
            {
                if (inventory[i]->getName() == "Snack")
                {
                    std::cout << i + 1 << ". " << inventory[i]->getName() << " - " << inventory[i]->getDescription() << "  counts: " << item_number[4] << std::endl;
                }
                else if (inventory[i]->getName() == "Heavy Textbook")
                {
                    std::cout << i + 1 << ". " << inventory[i]->getName() << " - " << inventory[i]->getDescription() << "  counts: " << item_number[3] << std::endl;
                }
                else if (inventory[i]->getName() == "Chalk")
                {
                    std::cout << i + 1 << ". " << inventory[i]->getName() << " - " << inventory[i]->getDescription() << "  counts: " << item_number[2] << std::endl;
                }
                else if (inventory[i]->getName() == "Blackboard Eraser")
                {
                    std::cout << i + 1 << ". " << inventory[i]->getName() << " - " << inventory[i]->getDescription() << "  counts: " << item_number[1] << std::endl;
                }
                else
                {
                    std::cout << i + 1 << ". " << inventory[i]->getName() << " - " << inventory[i]->getDescription() << std::endl;
                }
            }
            else
            {
                std::cout << i + 1 << ". [Empty Slot - Error!]" << std::endl;
            }
        }
    }
    std::cout << "---------------------------" << std::endl;
}

// --- Player-Specific Methods ---
void Player::useItem(size_t inventoryIndex)
{
    if (!isAlive())
    {
        std::cout << "Cannot use items while incapacitated." << std::endl;
        return;
    }
    size_t actualIndex;
    for (int i = 0; i < inventory.size(); i++)
    {
        if (inventory[i]->getName() == "Snack")
        {
            actualIndex = i;
            break;
        }
    }

    if (actualIndex >= inventory.size())
    {
        std::cerr << "Invalid item number selected." << std::endl;
        return;
    }

    Item *itemToUse = inventory[actualIndex];
    if (!itemToUse)
    {
        std::cerr << "[Error] Null item found in inventory at index " << actualIndex << "." << std::endl;
        inventory.erase(inventory.begin() + actualIndex);
        return;
    }

    std::cout << "Using " << itemToUse->getName() << "..." << std::endl;

    unsigned healthGain = itemToUse->getHealthBonus();
    if (healthGain > 0)
    {
        unsigned currentHealth = getHealth();
        unsigned maxHP = getMaxHealth();
        unsigned newHealth = std::min(currentHealth + healthGain, maxHP);
        setHealth(newHealth);
        std::cout << "You recovered " << (newHealth - currentHealth) << " health. Current HP: " << getHealth() << "/" << getMaxHealth() << std::endl;
    }

    int maxHealthChange = itemToUse->getMaxHealthBonus();
    if (maxHealthChange != 0)
    {
        int newMaxHealthSigned = static_cast<int>(getMaxHealth()) + maxHealthChange;
        unsigned newMaxHealth = (newMaxHealthSigned > 0) ? static_cast<unsigned>(newMaxHealthSigned) : 0;
        setMaxHealth(newMaxHealth);

        if (maxHealthChange > 0)
            std::cout << "Your maximum health increased by " << maxHealthChange << ". Max HP: " << getMaxHealth() << std::endl;
        else
            std::cout << "Your maximum health decreased by " << -maxHealthChange << ". Max HP: " << getMaxHealth() << std::endl;

        if (itemToUse->getType() == "Snack")
        {
            std::cout << "You feel a burst of energy, but perhaps less resilient..." << std::endl;
        }
    }

    if (itemToUse->isConsumable())
    {
        std::cout << "You have used a" << itemToUse->getName() << std::endl;
        inventory.erase(inventory.begin() + actualIndex);
        delete itemToUse;
    }
    else
    {
        std::cout << itemToUse->getName() << " effect applied." << std::endl;
    }
}
void Player::applyItemPassiveEffect(const Item &item)
{
    unsigned currentAttack = getAttackPower();
    unsigned currentDefense = getDefensePower();
    unsigned maxdefense = getMaxdefensePower();

    setAttackPower(currentAttack + item.getAttackBonus());
    setDefensePower(((currentDefense + item.getDefenseBonus()) > maxdefense) ? maxdefense : currentAttack + item.getDefenseBonus());

    int maxHealthChange = item.getMaxHealthBonus();
    if (maxHealthChange != 0)
    {
        int newMaxHealthSigned = static_cast<int>(getMaxHealth()) + maxHealthChange;
        unsigned newMaxHealth = (newMaxHealthSigned > 0) ? static_cast<unsigned>(newMaxHealthSigned) : 0;
        setMaxHealth(newMaxHealth);
    }

    if (item.getAttackBonus() > 0)
        std::cout << "Your Attack increased by " << item.getAttackBonus() << "!" << std::endl;
    if (item.getDefenseBonus() > 0)
        std::cout << "Your Defense increased by " << item.getDefenseBonus() << "!" << std::endl;
    if (item.getMaxHealthBonus() > 0)
        std::cout << "Your Max Health increased by " << item.getMaxHealthBonus() << "!" << std::endl;
    if (item.getMaxHealthBonus() < 0)
        std::cout << "Your Max Health decreased by " << -item.getMaxHealthBonus() << "!" << std::endl;

    if (getHealth() > getMaxHealth())
    {
        setHealth(getMaxHealth());
    }
}

void Player::removeItemPassiveEffect(const Item &item)
{
    unsigned currentAttack = getAttackPower();
    unsigned currentDefense = getDefensePower();
    unsigned attackBonus = item.getAttackBonus();
    unsigned defenseBonus = item.getDefenseBonus();

    setAttackPower((currentAttack > attackBonus) ? currentAttack - attackBonus : 0);
    setDefensePower((currentDefense > defenseBonus) ? currentDefense - defenseBonus : 0);

    int maxHealthChange = item.getMaxHealthBonus();
    if (maxHealthChange != 0)
    {
        int newMaxHealthSigned = static_cast<int>(getMaxHealth()) - maxHealthChange;
        unsigned newMaxHealth = (newMaxHealthSigned > 0) ? static_cast<unsigned>(newMaxHealthSigned) : 0;
        setMaxHealth(newMaxHealth);
    }

    std::cout << "Passive effects of " << item.getName() << " removed." << std::endl;
    if (item.getAttackBonus() > 0)
        std::cout << "Your Attack decreased by " << item.getAttackBonus() << "." << std::endl;
    if (item.getDefenseBonus() > 0)
        std::cout << "Your Defense decreased by " << item.getDefenseBonus() << "." << std::endl;
    if (item.getMaxHealthBonus() > 0)
        std::cout << "Your Max Health decreased by " << item.getMaxHealthBonus() << "." << std::endl;
    if (item.getMaxHealthBonus() < 0)
        std::cout << "Your Max Health increased by " << -item.getMaxHealthBonus() << "." << std::endl;

    if (getHealth() > getMaxHealth())
    {
        setHealth(getMaxHealth());
    }
    if (getMaxHealth() == 0)
    {
        setHealth(0);
    }
}

// Flashlight status
bool Player::isFlashlightOn() const
{
    return flashlightOn && !flashlightBroken;
}

void Player::toggleFlashlight()
{
    if (flashlightBroken)
    {
        std::cout << "The flashlight is broken and cannot be turned on." << std::endl;
        flashlightOn = false;
    }
    else
    {
        flashlightOn = !flashlightOn;
        std::cout << "Flashlight turned " << (flashlightOn ? "ON." : "OFF.") << std::endl;
    }
}

bool Player::isFlashlightBroken() const
{
    return flashlightBroken;
}

void Player::breakFlashlight()
{
    if (!flashlightBroken)
    {
        std::cout << "The flashlight shatters!" << std::endl;
        flashlightBroken = true;
        flashlightOn = false;
    }
}

const std::vector<Item *> &Player::getInventory() const
{
    return inventory;
}

void Player::combatLoop(Character *enemy)
{
    std::cout << "\n--- Battle Start: " << enemy->getName() << " ---\n";
    while (enemy->isAlive() && this->getHealth() > 0)
    {
        std::cout << "Your HP: " << this->getHealth() << "/" << this->getMaxHealth() << "\n";
        std::cout << enemy->getName() << " HP: " << enemy->getHealth() << "/" << enemy->getMaxHealth() << "\n";

        std::cout << "Choose item to attack (press number '1' to use blackboard eraser, number '2' to use chalk), or 'r' to run: ";
        std::string input;
        std::cin >> input;

        if (input.empty())
        {
            std::cout << "Invalid input! You didn't enter anything.\n";
            continue; // 重新输入
        }
        // 输入是合法数字，转换为整数
        size_t index;
        // 检查是否是数字或 'r'/'R'
        if (input == "r" || input == "R")
        {
            std::cout << "You attempt to flee...\n";
            std::cout << "You successfully fled the battle!\n";
            // // !!! --- 在逃跑时删除敌人 --- !!!
            // delete enemy;
            // enemy = nullptr;
            // // !!! ------------------------------- !!!
            break;
        }
        else if (input[0] == '1' || input[0] == '2')
        {
            // 检查是否是纯数字
            if (input[0] == '1')
            {
                for (int i = 0; i < inventory.size(); i++)
                {
                    if (inventory[i]->getName() == "Blackboard Eraser")
                    {
                        index = i + 1;
                        if (item_number[1] == 0)
                        {
                            Item *itemToUse = inventory[i];
                            std::cout << itemToUse->getName() << " was used up." << std::endl;
                            inventory.erase(inventory.begin() + i);
                            delete itemToUse;
                        }
                        item_number[1]--;
                        break;
                    }
                }
            }
            else
            {
                for (int i = 0; i < inventory.size(); i++)
                {
                    if (inventory[i]->getName() == "Chalk")
                    {
                        index = i + 1;
                        if (item_number[2] == 0)
                        {
                            Item *itemToUse = inventory[i];
                            std::cout << itemToUse->getName() << " was used up." << std::endl;
                            inventory.erase(inventory.begin() + i);
                            delete itemToUse;
                        }
                        item_number[2]--;
                        break;
                    }
                }
            }

            if (index > 0 && index <= this->getInventory().size())
            {
                Item *item = this->getInventory()[index - 1];
                if (item && item->getAttackBonus() > 0)
                {
                    unsigned damage = item->getAttackBonus() + this->getAttackPower();
                    std::cout << "You use " << item->getName() << " to attack for " << damage << " damage!\n";
                    bool enemyStillAlive = enemy->takeDamage(damage);
                    if (!enemyStillAlive)
                    {
                        std::cout << "You defeated the " << enemy->getName() << "!\n";
                        ++*this;
                        break;
                    }

                    // 敌人回合
                    if (!enemy->attack(*this))
                    {
                        std::cout << "You were defeated by the " << enemy->getName() << "!\n";
                        this->health = 0;
                        // gameOver = true;
                        break;
                    }
                }
            }
            else
            {
                std::cout << "Invalid item selection.\n";
            }
        }
        else
        {
            std::cout << "Invalid input! Please enter a number or 'r' to run.\n";
            continue; // 如果输入无效，提示用户重新输入
        }
    }
}

unsigned int Player::getMaxdefensePower() const
{
    return 200;
}
